package textapp.business;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
import javax.servlet.http.HttpServletResponse;

import com.google.gson.Gson;

import textapp.connector.push.PushMessage;
import textapp.dao.UserDao;
import textapp.dao.model.User;

public class PushMessageService {
	
	public static void main(String[] args) {
		UserDao dao = new UserDao();
		User u = dao.findById(4);
		System.out.println("REG: "+u.getPushIdentity());
		PushMessageService service = new PushMessageService();
		PushMessage pm = new PushMessage();
		pm.setText("Test Push Text");
		pm.setType(pm.PUSH_TYPE_NORMAL_MESSAGE);
		try {
			boolean result = service.sendPushMessage(u.getPushIdentity(), String.valueOf("U"+u.getId()), pm, false);
			System.out.println(result);
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public static final String C2DM_SEND_ENDPOINT = "https://android.clients.google.com/c2dm/send";
	private static final String UPDATE_CLIENT_AUTH = "Update-Client-Auth";
    public static final String PARAM_REGISTRATION_ID = "registration_id";
    public static final String PARAM_DELAY_WHILE_IDLE = "delay_while_idle";    
    public static final String PARAM_COLLAPSE_KEY = "collapse_key";
	
    public static final String PARAM_JSONTEXT = "jsonPush";
    
    public boolean sendPushMessage(String registrationId, String collapse, PushMessage msg,
            boolean delayWhileIdle) throws IOException{
    	Gson gson = new Gson();
    	String jsonStr = gson.toJson(msg);
    	Map<String, String[]> params = new HashMap<String, String[]>();
        params.put("data."+PARAM_JSONTEXT, new String[] {jsonStr});
        
    	return sendPushMessageParams(registrationId, collapse, params, delayWhileIdle);
    }
    
	private boolean sendPushMessageParams(String registrationId, String collapse, Map<String, String[]> params,
            boolean delayWhileIdle) throws IOException{
		
		StringBuilder postDataBuilder = new StringBuilder();
		postDataBuilder.append(PARAM_REGISTRATION_ID).
        append("=").append(registrationId);

	    if (delayWhileIdle) {
	        postDataBuilder.append("&")
	            .append(PARAM_DELAY_WHILE_IDLE).append("=1");
	    }
	    postDataBuilder.append("&").append(PARAM_COLLAPSE_KEY).append("=").append(collapse);
	    for (Object keyObj: params.keySet()) {
            String key = (String) keyObj;
            if (key.startsWith("data.")) {
                String[] values = (String[]) params.get(key);
                postDataBuilder.append("&").append(key).append("=").
                    append(URLEncoder.encode(values[0], "UTF-8"));
            }
        }
	    
		byte[] postData = postDataBuilder.toString().getBytes("UTF-8");

		
        // Hit the dm URL.
        URL url = new URL(C2DM_SEND_ENDPOINT);
        
        HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
        conn.setHostnameVerifier(new CustomizedHostnameVerifier());
        conn.setDoOutput(true);
        conn.setUseCaches(false);
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        conn.setRequestProperty("Content-Length", Integer.toString(postData.length));
        
        AppConfigService apService = AppConfigService.getInstance();
        String authToken = apService.getPushAuthToken();
        conn.setRequestProperty("Authorization", "GoogleLogin auth=" + authToken);
        
        OutputStream out = conn.getOutputStream();
        out.write(postData);
        out.close();
        
        int responseCode = conn.getResponseCode();
        
        if (responseCode == HttpServletResponse.SC_UNAUTHORIZED ||
                responseCode == HttpServletResponse.SC_FORBIDDEN) {
        	return false;
        }
        
        // Check for updated token header
        String updatedAuthToken = conn.getHeaderField(UPDATE_CLIENT_AUTH);
        if (updatedAuthToken != null && !authToken.equals(updatedAuthToken)) {
        	apService.saveOrUpdatePushAuthToken(updatedAuthToken);
        }
        
        String responseLine = new BufferedReader(new InputStreamReader(conn.getInputStream()))
        .readLine();
        
	    // NOTE: You *MUST* use exponential backoff if you receive a 503 response code.
	    // Since App Engine's task queue mechanism automatically does this for tasks that
	    // return non-success error codes, this is not explicitly implemented here.
	    // If we weren't using App Engine, we'd need to manually implement this.
	    //log.info("Got " + responseCode + " response from Google C2DM endpoint.");
	    
	    if (responseLine == null || responseLine.equals("")) {
	        throw new IOException("Got empty response from Google C2DM endpoint.");
	    }
	
	    String[] responseParts = responseLine.split("=", 2);
	    if (responseParts.length != 2) {
	        //log.warning("Invalid message from google: " + responseCode + " " + responseLine);
	        throw new IOException("Invalid response from Google " + 
	                responseCode + " " + responseLine);
	    }
	
	    if (responseParts[0].equals("id")) {
	        //log.info("Successfully sent data message to device: " + responseLine);
	        return true;
	    }
	    
	    if (responseParts[0].equals("Error")) {
	        String err = responseParts[1];
	        //log.warning("Got error response from Google C2DM endpoint: " + err);
	        // No retry. 
	        // TODO(costin): show a nicer error to the user.
	        throw new IOException("Server error: " + err);
	    } else {
	        // 500 or unparseable response - server error, needs to retry
	        //log.warning("Invalid response from google " + responseLine + " " + responseCode);
	        return false;
	    }

	}
	
	public static boolean isPushAble(User u) {
		if (u == null) {
			return false;
		}
		
		String iden = u.getPushIdentity();
		if (iden == null || iden.length() < 5) {
			return false;
		}
		return true;
	}
	
	private static class CustomizedHostnameVerifier implements HostnameVerifier {
		 public boolean verify(String hostname, SSLSession session) {
		  return true;
		 }
	}
	
	
	
}


